package objects;

import com.sun.j3d.utils.image.TextureLoader;
import javax.media.j3d.*;
import javax.vecmath.*;

/**
 * Erzeugung der Mauer
 *
 * @version 1.0
 * @author Dennis Wittkoetter
 * @author Imanuel Rohlfing
 */
public class Wall {

    /**
     * BranchGroup fuer die Mauer
     */
    private BranchGroup wallBG;

    /**
     * Konstruiert die Mauer und fuegt sie der BranchGroup hinzu.
     */
    public Wall() {
        wallBG = new BranchGroup();

        //Eckpunkte der Wand
        Point3f points[] = {
            new Point3f(-0.1f, -1.5f, -2.0f),
            new Point3f(-0.1f, -1.5f, 2.0f),
            new Point3f(-0.1f, 1.5f, -2.0f),
            new Point3f(-0.1f, 1.5f, 2.0f),
            new Point3f(0.1f, -1.5f, -2.0f),
            new Point3f(0.1f, -1.5f, 2.0f),
            new Point3f(0.1f, 1.5f, -2.0f),
            new Point3f(0.1f, 1.5f, 2.0f),};

        //Textur-Koordinaten (vorne)
        TexCoord2f[] textCoordFront = {
            new TexCoord2f(6.0f, 0.0f),
            new TexCoord2f(0.0f, 0.0f),
            new TexCoord2f(0.0f, 4.0f),
            new TexCoord2f(6.0f, 4.0f)
        };

        //Textur-Koordinaten (hinten)
        TexCoord2f[] textCoordBack = {
            new TexCoord2f(8.0f, 0.0f),
            new TexCoord2f(0.0f, 0.0f),
            new TexCoord2f(0.0f, 6.0f),
            new TexCoord2f(8.0f, 6.0f)
        };

        //Textur-Koordinaten (oben)
        TexCoord2f[] textCoordTop = {
            new TexCoord2f(0.0f, 0.0f),
            new TexCoord2f(0.0f, 8.0f),
            new TexCoord2f(1.0f, 8.0f),
            new TexCoord2f(1.0f, 0.0f)
        };

        //Textur-Koordinaten (links/rechts)
        TexCoord2f[] textCoordSide = {
            new TexCoord2f(1.0f, 0.0f),
            new TexCoord2f(0.0f, 0.0f),
            new TexCoord2f(0.0f, 24.0f),
            new TexCoord2f(1.0f, 24.0f)
        };

        //Flaechen-Normalen
        Vector3f[] normals = {
            new Vector3f(-1.0f, 0.0f, 0.0f),    // vorne
            new Vector3f(1.0f, 0.0f, 0.0f),     // hinten
            new Vector3f(0.0f, 0.0f, 1.0f),     // rechts
            new Vector3f(0.0f, 0.0f, -1.0f),    // links
            new Vector3f(0.0f, 1.0f, 0.0f),     // oben
            new Vector3f(0.0f, -1.0f, 0.0f)     // unten
        };

        /*
         * Seitenwaende aus Punkten, Texturkoordinaten und Normalen
         * zusammensetzen Texturkoordinaten und Normalen dienen zur korrekten
         * Darstellung der Texturen und der Beleuchtung
         */
        QuadArray vorne, hinten, links, rechts, oben, unten;

        vorne = new QuadArray(4, QuadArray.COORDINATES | QuadArray.TEXTURE_COORDINATE_2 | QuadArray.NORMALS);
        vorne.setCoordinate(0, points[0]);
        vorne.setCoordinate(1, points[1]);
        vorne.setCoordinate(2, points[3]);
        vorne.setCoordinate(3, points[2]);
        vorne.setTextureCoordinates(0, 0, textCoordFront);
        for (int i = 0; i < 4; i++) {
            vorne.setNormal(i, normals[0]);
        }

        hinten = new QuadArray(4, QuadArray.COORDINATES | QuadArray.TEXTURE_COORDINATE_2 | QuadArray.NORMALS);
        hinten.setCoordinate(0, points[5]);
        hinten.setCoordinate(1, points[4]);
        hinten.setCoordinate(2, points[6]);
        hinten.setCoordinate(3, points[7]);
        hinten.setTextureCoordinates(0, 0, textCoordBack);
        for (int i = 0; i < 4; i++) {
            hinten.setNormal(i, normals[1]);
        }

        rechts = new QuadArray(4, QuadArray.COORDINATES | QuadArray.TEXTURE_COORDINATE_2 | QuadArray.NORMALS);
        rechts.setCoordinate(0, points[1]);
        rechts.setCoordinate(1, points[5]);
        rechts.setCoordinate(2, points[7]);
        rechts.setCoordinate(3, points[3]);
        rechts.setTextureCoordinates(0, 0, textCoordSide);
        for (int i = 0; i < 4; i++) {
            rechts.setNormal(i, normals[2]);
        }

        links = new QuadArray(4, QuadArray.COORDINATES | QuadArray.TEXTURE_COORDINATE_2 | QuadArray.NORMALS);
        links.setCoordinate(0, points[4]);
        links.setCoordinate(1, points[0]);
        links.setCoordinate(2, points[2]);
        links.setCoordinate(3, points[6]);
        links.setTextureCoordinates(0, 0, textCoordSide);
        for (int i = 0; i < 4; i++) {
            links.setNormal(i, normals[3]);
        }

        oben = new QuadArray(4, QuadArray.COORDINATES | QuadArray.TEXTURE_COORDINATE_2 | QuadArray.NORMALS);
        oben.setCoordinate(0, points[2]);
        oben.setCoordinate(1, points[3]);
        oben.setCoordinate(2, points[7]);
        oben.setCoordinate(3, points[6]);
        oben.setTextureCoordinates(0, 0, textCoordTop);
        for (int i = 0; i < 4; i++) {
            oben.setNormal(i, normals[4]);
        }

        unten = new QuadArray(4, QuadArray.COORDINATES | QuadArray.TEXTURE_COORDINATE_2 | QuadArray.NORMALS);
        unten.setCoordinate(0, points[4]);
        unten.setCoordinate(1, points[5]);
        unten.setCoordinate(2, points[1]);
        unten.setCoordinate(3, points[0]);
        unten.setTextureCoordinates(0, 0, textCoordTop);
        for (int i = 0; i < 4; i++) {
            unten.setNormal(i, normals[5]);
        }

        //TransformGroup zur Skalierung der Mauer
        Transform3D translate = new Transform3D();
        translate.setScale(0.4);
        TransformGroup wallTG = new TransformGroup();
        wallTG.setTransform(translate);

        //Flaechen erstellen und UserDate setzen
        Shape3D wall_front = new Shape3D(vorne, texture("textures/tapete.jpg"));
        wall_front.setUserData("Tapete");
        Shape3D wall_back = new Shape3D(hinten, texture("textures/ziegel_front.jpg"));
        wall_back.setUserData("Wand-hinten");
        Shape3D wall_left = new Shape3D(links, texture("textures/ziegel_seite.jpg"));
        wall_left.setUserData("Wand-links");
        Shape3D wall_right = new Shape3D(rechts, texture("textures/ziegel_seite.jpg"));
        wall_right.setUserData("Wand-rechts");
        Shape3D wall_top = new Shape3D(oben, texture("textures/ziegel_oben.jpg"));
        wall_top.setUserData("Wand-oben");
        Shape3D wall_bottom = new Shape3D(unten, texture("textures/ziegel_oben.jpg"));
        wall_bottom.setUserData("Wand-unten");


        //Flaechen zur BranchGroup hinzufuegen
        wallTG.addChild(wall_front);
        wallTG.addChild(wall_back);
        wallTG.addChild(wall_left);
        wallTG.addChild(wall_right);
        wallTG.addChild(wall_top);
        wallTG.addChild(wall_bottom);

        wallBG.addChild(wallTG);
    }

    /**
     * Laed die Textur aus einem Pfad
     *
     * @param s	Pfad zur Textur
     * @return
     */
    private Appearance texture(String s) {    	
        java.net.URL url = ClassLoader.getSystemResource( s );
        TextureLoader loader = new TextureLoader(url, null);
        ImageComponent2D image = loader.getImage();
        Texture2D texture = new Texture2D();
        int form = texture.getFormat();
        int base = texture.getMipMapMode();
        if (System.getProperty("os.name").contains("Windows")) {
        	texture = new Texture2D(base, form, loader.getImage().getWidth(), loader.getImage().getHeight());
        } else {
        	texture = new Texture2D(base, form, 512, 512);
        }
        texture.setImage(0, image);

        texture.setBoundaryModeS(Texture.WRAP);
        texture.setBoundaryModeT(Texture.WRAP);
        texture.setBoundaryColor(new Color4f(0.0f, 1.0f, 0.0f, 0.0f));
        Appearance appear = new Appearance();
        appear.setTexture(texture);
        TextureAttributes texat = new TextureAttributes(TextureAttributes.MODULATE, new Transform3D(), new Color4f(), TextureAttributes.NICEST);
        appear.setTextureAttributes(texat);
        appear.setMaterial(new Material());
        return (appear);
    }

    /**
     * Liefert Branchgroup der Mauer-Flaechen.
     *
     * @return
     */
    public BranchGroup get() {
        return wallBG;
    }
}